package com.funi;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**********************************************************************
 * &lt;p&gt;文件名：FileLineCounter.java &lt;/p&gt;
 * &lt;p&gt;文件描述：代码行数统计(描述该文件做什么) 
 * @project_name：code_total
 * @author zengshunyao
 * @create 2025/9/2 12:02
 * @history
 * @department：政务事业部
 * Copyright ChengDu Funi Cloud Code Technology Development CO.,LTD 2014 
 *                    All Rights Reserved.
 */

/**
 * 目录文件行数统计工具
 * 功能：递归扫描指定目录及子目录下指定后缀的文件，并计算总行数
 * 使用示例：修改main方法中的directoryPath和suffixes参数即可运行
 */
public class FileLineCounter {

    public static void main(String[] args) {
        // 设置要扫描的目录路径（请修改为您的实际路径）
        final String directoryPath = "/Users/apple/work/funi/gitlab_software_park/funi-platform-cdpsfs-web/src/main";
        // 设置要统计的文件后缀（可同时统计多种类型）
        final String[] suffixes = {".java", ".xml", ".js"}; // 可以添加或修改需要的后缀

        try {
            System.out.println("开始统计目录: " + directoryPath);
            System.out.println("目标文件类型: " + String.join(", ", suffixes));
            System.out.println("----------------------------------------");

            // 执行统计
            final long totalLines = countFilesLines(directoryPath, suffixes);

            System.out.println("----------------------------------------");
            System.out.println("统计完成！总行数: " + totalLines);
        } catch (Exception e) {
            System.err.println("执行过程中出现错误: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 递归统计指定目录下特定后缀文件的行数
     *
     * @param directoryPath 目录路径
     * @param suffixes      文件后缀数组
     * @return 总行数
     */
    private static long countFilesLines(String directoryPath, String[] suffixes) {
        // 用于存储找到的文件
        final List<File> fileList = new ArrayList<>();
        // 用于原子操作统计总行数
        final AtomicLong totalLines = new AtomicLong(0);

        // 第一步：递归查找所有指定后缀的文件
        findFilesBySuffix(new File(directoryPath), suffixes, fileList);

        // 第二步：逐个统计文件行数并累加
        fileList.forEach(file -> {
            try {
                long lineCount = countSingleFileLines(file);
                totalLines.addAndGet(lineCount);
                // 输出每个文件的统计结果
                System.out.println(file.getAbsolutePath() + " --> 行数: " + lineCount);
            } catch (IOException e) {
                System.err.println("无法读取文件: " + file.getAbsolutePath() + ", 错误: " + e.getMessage());
            }
        });

        return totalLines.get();
    }

    /**
     * 递归查找指定后缀的文件
     *
     * @param directory 要查找的目录
     * @param suffixes  文件后缀数组
     * @param fileList  存储匹配文件的列表
     */
    private static void findFilesBySuffix(File directory, String[] suffixes, List<File> fileList) {
        if (directory == null || !directory.exists() || !directory.isDirectory()) {
            System.err.println("目录不存在或不是有效目录: " + directory);
            return;
        }

        final File[] files = directory.listFiles();
        if (files == null) {
            return;
        }

        for (File file : files) {
            if (file.isDirectory()) {
                // 递归遍历子目录
                findFilesBySuffix(file, suffixes, fileList);
            } else {
                // 检查文件后缀是否匹配
                for (String suffix : suffixes) {
                    if (file.getName().toLowerCase().endsWith(suffix.toLowerCase())) {
                        fileList.add(file);
                        break;
                    }
                }
            }
        }
    }

    /**
     * 统计单个文件的行数
     *
     * @param file 要统计的文件
     * @return 文件行数
     * @throws IOException 当文件读取失败时抛出
     */
    private static long countSingleFileLines(File file) throws IOException {
        long lineCount = 0;

        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            while (reader.readLine() != null) {
                lineCount++;
            }
        }
        return lineCount;
    }
}
